/*
作用：一些用于资源管理器文件操作功能的函数
作者：孙泽宇
属于mvc框架中的c层
*/

#include<stdio.h>
#include<stdlib.h>
#include<dos.h>
#include<dir.h>
#include<string.h>
#include"filestruct.h"
#include"disk.h"
#include"file.h"
#define N 50		//文件路径字符串大小
/*
作用：迭代释放节点内存
输入：根节点
输出：无
返回值：无
*/
void free_node(file_node *root)
{
	char head = 0;
	char tail = 0;
	file_node **a;//队列
	file_node *p;//循环辅助
	a = (file_node **)malloc(100*sizeof(file_node *));
	if(a == NULL)
	{
		printf("memory");
		exit(1);
	}
	a[tail++] = root;
	while(head < tail)
	{
		p = a[head++];
		if(p->child != NULL)
		{
			a[tail++] = p->child;
		}
		if(p->next != NULL)
		{
			a[tail++] = p->next;
		}
		free(p);
		p = NULL;
	}
	free(a);
	return;
}

/*
作用：将find_t结构中的数据转换为file_info
输入：find_t结构，file_info结构
输出：无
返回值：无
*/
void translate_filestruct(struct find_t *f,file_info *file)
{
	char i = 0;//循环辅助变量
	for(i = 0; i < 13; i++)
	{
		file->name[i] = 0;
	}
	strcpy(file->name,f->name);
	file->type = f->attrib;
	file->time = f->wr_time;
	file->date = f->wr_date;
	file->size = f->size;		//ffblk中若为文件夹，大小为0,以b为单位
}

/*
作用：node初始化
输入：file_node指针
输出：无
返回值：无
*/
void malloc_init_node(file_node *p)
{
	char i = 0;//循环辅助变量
	for(i = 0; i < 13; i++)
	{
		p->file.name[i] = 0;
	}
	p->file.type = 0;
	p->file.time = 0;
	p->file.date = 0;
	p->file.size = 0;
	p->pre = NULL;
	p->next = NULL;
	p->child = NULL;
	return;
}

/*
作用：find_t结构初始化
输入：find_t指针
输出：无
返回值：无
*/
void malloc_init_ft(struct find_t *p)
{
	char i = 0;
	for(i = 0; i < 21; i++)
	{
		p->reserved[i] = 0;
	}
	for(i = 0; i < 13; i++)
	{
		p->name[i] = '\0';
	}
	p->attrib = 0;
	p->wr_date = 0;
	p->wr_time = 0;
	p->size = 0;
	return;
}

/*
作用：info初始化
输入：info指针
输出：无
返回值：无
*/
void malloc_init_info(file_info *p)
{
	char i = 0;
	for(i = 0; i < 13; i++)
	{
		p->name[i] = '\0';
	}
	p->type = 0;
	p->time = 0;
	p->date = 0;
	p->size = 0;
	return;
}

/*
作用：磁盘初始化
输入：无
输出：无
返回值：根节点
*/
file_node *diskc_init()
{
	int handle;
	char strtemp[N] = "c:\\";		//储存路径
	struct find_t *f;
	file_info *file;
	file_node *root;		//根节点
	file_node *temp;		//临时节点1
	file_node *p;			//临时节点2
	root = (file_node *)malloc(sizeof(file_node));
	temp = (file_node *)malloc(sizeof(file_node));
	f = (struct find_t *)malloc(sizeof(struct find_t));
	file = (file_info *)malloc(sizeof(file_info));
	if(root == NULL)	//动态内存分配
	{
		printf("memory");
		exit(1);
	}
	malloc_init_node(root);
	if(temp == NULL)	//动态内存分配
	{
		printf("memory");
		exit(1);
	}
	malloc_init_node(temp);
	if(f == NULL)		//动态内存分配
	{
		printf("memory");
		exit(1);
	}
	malloc_init_ft(f);
	if(file == NULL)	//动态内存分配
	{
		printf("memory");
		exit(1);
	}
	malloc_init_info(file);
	setdisk(2);
	chdir(strtemp);
	handle = _dos_findfirst("*.*",0xff,f);
	if(handle == -1)
	{
		printf("findfirst error#1 ");
	}
	translate_filestruct(f,file);
	root->file = *file;			//C_drive
	for(handle = 0;handle < 13; handle++)
	{
		root->file.name[handle] = '\0';
	}
	handle = 0;
	strcpy(root->file.name,"C:");
	root->file.type = 8;
	_dos_findnext(f);
	while((strcmp(f->name,".") == 0) || (strcmp(f->name,"..") == 0)) 	//跳过.和..
	{
		_dos_findnext(f);
	}
	translate_filestruct(f,file);
	temp->file = *file;
	if(temp->file.type == 16)
	{
		temp->file.type = 2;
	}
	else if(temp->file.type == 32)
	{
		temp->file.type = 1;
	}
	root->child = temp;
	temp->pre = root;
	temp->file.type = temp->file.type |	32;
	while(!_dos_findnext(f))
	{
		p = (file_node *)malloc(sizeof(file_node));
		if(p == NULL)
		{
			printf("memory");
			exit(1);
		}
		malloc_init_node(p);
		translate_filestruct(f,file);
		p->file = *file;
		if(p->file.type == 16)
		{
			p->file.type = 2;
		}
		else if(p->file.type == 32)
		{
			p->file.type = 1;
		}
		temp->next = p;
		p->pre = temp;
		temp = p;
		}
	//以上实现c盘根节点及第一级链表的初始化
	//temp = root->child;
	//borlandc过大
	temp = root->child->next;
	while((temp->file.type & 2) == 2)
	{
		p = (file_node *)malloc(sizeof(file_node));
		if(p == NULL)
		{
			printf("memory");
			exit(1);
		}
		malloc_init_node(p);
		temp->child = p;
		p->pre = temp;
		p->file.type = p->file.type | 32;
		strcpy(strtemp,"c:\\");
		strcat(strtemp,temp->file.name);
		strcat(strtemp,"\\");
		addnode(strtemp,p);
		temp = temp->next;
	}
	putin_level(root,0);
	type_update(root);
	free(f);
	free(file);
	return root;
}

/*
作用：递归目录节点接入
输入：路径，头节点
输出：无
返回值：无
*/
void addnode_dir(char *path,file_node *head)
{
	int handle;
	char strtemp[N];		//储存文件夹名
	char i = 0;				//循环辅助变量
	char j = 0;				//循环辅助变量
	struct find_t *f;
	file_info *file;
	file_node *temp;		//临时节点1
	file_node *p;			//临时节点2
	temp = head;
	strcpy(strtemp,path);
	chdir(path);
	f = (struct find_t *)malloc(sizeof(struct find_t));
	if(f == NULL)
	{
		printf("memory");
		exit(1);
	}
	malloc_init_ft(f);
	file = (file_info *)malloc(sizeof(file_info));
	if(file == NULL)
	{
		printf("memory");
		exit(1);
	}
	malloc_init_info(file);
	handle = _dos_findfirst("*.*",0xff,f);
	if(handle == -1)
	{
		printf("findfirst error#2 ");
	}
	while(((strcmp(f->name,".") == 0) || (strcmp(f->name,"..") == 0)) && (j < 3))//跳过.和..及防止文件夹为空导致死循环
	{
		_dos_findnext(f);
		j++;
	}
	
	if(j < 3)
	{	
		translate_filestruct(f,file);
		temp->file = *file;
		if(temp->file.type == 16)
		{
			temp->file.type = 2;
			temp->file.type = temp->file.type | 32;
		}
		else if(temp->file.type == 32)
		{
			temp->file.type = 1;
			temp->file.type = temp->file.type | 32;
		}
	}
	else
	{
		temp->pre->child = NULL;
		free(temp);
		free(f);
		free(file);
		return;
	}
	if(f->attrib == 16)
	{
		i++;
	}
	while(!_dos_findnext(f))		//广度优先算法实现兄弟节点链接
	{
		if(f->attrib == 16)
		{
			p = (file_node *)malloc(sizeof(file_node));
			if(p == NULL)
			{
				printf("memory");
				exit(1);
			}
			malloc_init_node(p);
			translate_filestruct(f,file);
			p->file = *file;
			p->file.type = 2;
			temp->next = p;
			p->pre = temp;
			temp = p;
			i++;
		}
		if(f->attrib == 32)
		{
			p = (file_node *)malloc(sizeof(file_node));
			if(p == NULL)
			{
				printf("memory");
			}
			malloc_init_node(p);
			addnode_file(p);
			p->pre = temp;
			temp->next = p;
			break;
		}
	}
	while(i > 0)
	{
		strcpy(strtemp,path);
		strcat(strtemp,head->file.name);
		strcat(strtemp,"\\");
		p = (file_node *)malloc(sizeof(file_node));
		if(p == NULL)
		{
			printf("memory");
			exit(1);
		}
		malloc_init_node(p);
		head->child = p;
		p->pre = head;
		head = head->next;
		addnode_dir(strtemp,p);
		i--;
	}
	free(f);
	free(file);
}

/*
作用：文件节点接入
输入：头节点
输出：无
返回值：无
*/
void addnode_file(file_node *head)
{
	int handle;
	char i = 0;			//循环辅助变量
	struct find_t *f;
	file_info *file;
	file_node *temp;		//临时节点1
	file_node *p;			//临时节点2
	temp = head;
	f = (struct find_t *)malloc(sizeof(struct find_t));
	if(f == NULL)
	{
		printf("memory");
		exit(1);
	}
	malloc_init_ft(f);
	file = (file_info *)malloc(sizeof(file_info));
	if(file == NULL)
	{
		printf("memory");
		exit(1);
	}
	malloc_init_info(file);
	handle = _dos_findfirst("*.*",0xff,f);
	if(handle == -1)
	{
		printf("findfirst error#5 ");
	}
	while(((strcmp(f->name,".") == 0) || (strcmp(f->name,"..") == 0)) && (i < 3))//跳过.和..及防止文件夹为空导致死循环
	{
		_dos_findnext(f);
		i++;
	}
	if(i >= 3)
	{
		free(temp);
		free(f);
		free(file);
		return;
	}
	while(f->attrib != 32)
	{
		_dos_findnext(f);
	}
	translate_filestruct(f,file);
	if(temp->file.name[0] == 0)
	{
		if((temp->file.type & 32) == 32)
		{
			temp->file = *file;
			temp->file.type = 33;
		}
		else
		{	
		temp->file = *file;
		temp->file.type = 1;
		}
	}
	while(!_dos_findnext(f))
	{
		p = (file_node *)malloc(sizeof(file_node));
		if(p == NULL)
		{
			printf("memory");
			exit(1);
		}
		malloc_init_node(p);
		translate_filestruct(f,file);
		p->file = *file;
		p->file.type = 1;
		temp->next = p;
		p->pre = temp;
		temp = p;
	}
	free(f);
	free(file);
}

/*
作用：判断调用接入节点类型
输入：路径,头节点(某目录子链表第二个元素，即该路径下的第一个位置)
输出：无
返回值：无
*/
void addnode(char *path,file_node *head)
{
	char i = 0;			//循环辅助变量
	int handle;
	struct find_t *f;
	f = (struct find_t *)malloc(sizeof(struct find_t));
	if(f == NULL)
	{
		printf("memory");
		exit(1);
	}
	malloc_init_ft(f);
	chdir(path);
	handle = _dos_findfirst("*.*",0xff,f);
	if(handle == -1)
	{
		return;
	}
	while(((strcmp(f->name,".") == 0) || (strcmp(f->name,"..") == 0)) && (i < 3))//跳过.和..及防止文件夹为空导致死循环
	{
		_dos_findnext(f);
		i++;
	}
	if(i >= 3)
	{
		free(f);
		return;
	}
	if(f->attrib == 32)
	{
		addnode_file(head);
	}
	if(f->attrib == 16)
	{
		addnode_dir(path,head);
	}
	free(f);
}

/*
作用：文件层级录入(递归写法)
输入：根节点，根节点所在层级n
输出：无
返回值：无
*/
void putin_level(file_node *root,int n)
{
	if(n == 0)
	{
		root->file.time = root->file.time & 65504;
	}
	if(n == 1)
	{
		root->file.time = root->file.time & 65504;
		root->file.time = root->file.time | 1;
	}
	if(n == 2)
	{
		root->file.time = root->file.time & 65504;
		root->file.time = root->file.time | 2;
	}
	if(n == 3)
	{
		root->file.time = root->file.time & 65504;
		root->file.time = root->file.time | 4;
	}
	if(n == 4)
	{
		root->file.time = root->file.time & 65504;
		root->file.time = root->file.time | 8;
	}
	if(n == 5)
	{
		root->file.time = root->file.time & 65504;
		root->file.time = root->file.time |16;
	}
	if(root->child != NULL)
	{
		putin_level(root->child,n+1);
	}
	if(root->next != NULL)
	{
		putin_level(root->next,n);
	}
	return;
}

/*
作用：同步上次修改
输入：根节点
输出：无
返回值：无
*/
void type_update(file_node *root)
{
	char name[13];
	char size[5];
	long k = 0;
	char path[N];
	char mode[3];
	FILE *fp;
	file_node *p;
	for(k = 0; k < 13; k++)
	{
		name[k] = '\0';
	}
	for(k = 0; k < 5; k++)
	{
		size[k] = '\0';
	}
	for(k = 0; k < N; k++)
	{
		path[k] = '\0';
	}
	for(k = 0; k < 3; k++)
	{
		mode[k] = '\0';
	}
	k = 0;
	chdir("c:\\hanziku\\");
	fp = fopen("type.txt","r");
	k = fgetc(fp);
	while(feof(fp) == 0)
	{
		if(k == -1)
		{
			rewind(fp);
		}
		myfgets(name,13,fp);
		myfgets(size,5,fp);
		chartolong(&k,size);
		myfgets(path,N,fp);
		myfgets(mode,3,fp);
		p = find_node(name,k,path,root);
		if(p == NULL)
		{
			continue;
		}
		if(strcmp(mode,"h0") == 0)
		{
			p->file.type = p->file.type | 4;
		}
		if(strcmp(mode,"s0") == 0)
		{
			p->file.type = p->file.type | 16;
		}
		if(strcmp(mode,"h1") == 0)
		{
			p->file.type = p->file.type ^ 4;
		}
		if(strcmp(mode,"s1") == 0)
		{
			p->file.type = p->file.type ^ 16;
		}
	}
	fclose(fp);
}